package com.fdb.efp.nls.service.impl.yed.sx;

import com.alibaba.fastjson.JSONObject;
import com.fdb.efp.nls.service.facade.NlsStageInfoService;
import com.fdb.efp.nls.service.facade.sx.NlsCreditInfoService;
import com.fdb.efp.nls.service.facade.yed.YedGjjLoanService;
import com.fdb.efp.nls.service.facade.yed.YedSqsSignatureService;
import com.fdb.efp.nls.service.facade.yed.YedSxCtrSignatureService;
import com.fdb.efp.nls.service.vo.NlsCreditInfoNoticeVO;
import com.fdb.efp.nls.service.vo.NlsStageInfoVO;
import com.fdb.efp.nls.service.vo.queue.NlsProcessBizVO;
import com.fdb.efp.nls.service.vo.sx.NlsCreditInfoVO;
import com.fdb.basic.framework.core.base.FrameworkService;
import com.fdb.basic.framework.core.constant.BaseConstant;
import com.fdb.basic.framework.core.constant.DateFormatConstant;
import com.fdb.basic.framework.core.constant.ESBConstant;
import com.fdb.basic.framework.core.exception.BizException;
import com.fdb.basic.framework.core.threadpool.ApplicationThreadPool2;
import com.fdb.basic.framework.core.util.RandomCodeUtils;
import com.fdb.basic.framework.core.util.SpringContextUtils;
import com.fdb.basic.framework.core.util.StringUtil;
import com.fdb.basic.framework.core.util.TimeUtil;
import com.fdb.basic.sequence.service.DefaultPatternDescriptor;
import com.fdb.basic.sequence.service.PatternDescriptor;
import com.fdb.basic.sequence.service.facade.PatternedLimitableSeqService;
import com.fdb.efp.nls.common.ConsoleConstant;
import com.fdb.efp.nls.service.facade.PubSysInfoService;
import com.fdb.efp.cus.service.facade.CusReferrerInfoService;
import com.fdb.efp.cus.service.vo.CusReferrerInfoVO;
import com.fdb.efp.cus.service.vo.KafkaNoticeHeader;
import com.fdb.efp.nls.service.facade.yed.YedImageFileAnalysisService;
import com.fdb.efp.esb.common.constant.MsLoanConstant;
import com.fdb.efp.esb.service.bo.req.sed.letter.ReqSedLetterBean;
import com.fdb.efp.esb.service.facade.sed.letter.SedLetterInformService;
import com.fdb.efp.limit.service.facade.LmtPrdContService;
import com.fdb.efp.limit.service.vo.LmtPrdContNoticeVO;
import com.fdb.efp.limit.service.vo.LmtPrdContVO;
import com.fdb.efp.nls.common.util.KafkaUtil;
import com.fdb.efp.nls.service.impl.sx.CreditSoltServiceImpl;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

import static com.fdb.basic.sequence.service.DefaultPatternDescriptor.*;

/**
 * 需求编号：优e贷额度生成插槽<br/>
 * 问题编号：<br/>
 * 功能描述：<br/>
 * 开发人员：dengqiwen<br/>
 * 创建时间：2020/7/31 9:41
 */
@Service("yedCreditLmtService")
public class YedCreditLmtServiceImpl  extends CreditSoltServiceImpl  implements FrameworkService {
    /**
     * 日志信息
     */
    private final Logger logger = LoggerFactory.getLogger(YedCreditLmtServiceImpl.class);
    /**
     * 日志模板
     */
    private final String msgTemplate = "message{}";
    /**
     * 额度流水生成PATTERN
     */
    private static final PatternDescriptor PATTERN = DefaultPatternDescriptor.of("lmt" + YEAR_4 + MONTH + DAY + SEQ, 8);


    @Autowired
    @Qualifier("yedImageFileAnalysisService")
    private YedImageFileAnalysisService yedImageFileAnalysisService;

    // kafka主机IP地址
    @Value("${risk.kafkaServers}")
    private String kafkaServers;

    // kafka发送的主题topic
    @Value("${risk.kafkaToptic}")
    private String kafkaToptic;

    @Value("${yed.download.url}")
    private  String url;


    @Override
    protected void doExecute(NlsProcessBizVO nlsProcessBizVo, NlsCreditInfoVO nlsCreditInfoVO) throws Exception {
        // 流水号
        String applySeq = nlsProcessBizVo.getApplySeq();
        logger.info("======>优e贷生成额度信息服务开始,流水号" + applySeq + "<======");

        try {
            // 根据授信申请流水号查询额度信息是否存在
            boolean isLimitExits = getLimitByLmtApplySeq(nlsCreditInfoVO);

            if (isLimitExits) {
                String openday = pubSysInfoService.getOpenday(BaseConstant.SYS_ID_1001);
                //签订综合委托授权书
                String[] yedStr = yedSqsSignatureService.signature(nlsCreditInfoVO);
                if(!ESBConstant.SUCCESS.equals(yedStr[0])){
                    throw new Exception("授信流水号："+nlsCreditInfoVO.getLmtApplySeq()+"签订综合委托授权书异常!");
                }

                //签订授信合同
                String[] strings = yedSxCtrSignatureService.sxSignature(nlsCreditInfoVO);
                if(!ESBConstant.SUCCESS.equals(strings[0])){
                    throw new Exception("授信流水号："+nlsCreditInfoVO.getLmtApplySeq()+"签订授信合同异常!");
                }

                // 不存在则，插入一条未生效的额度信息
                insertProLmtCont(nlsCreditInfoVO,openday);
                // 修改推荐人信息表
                updateCusReferrerInfo(nlsCreditInfoVO,openday);
                //更新授信表授信审批状态为通过
                updateCreditApplyInfo(nlsCreditInfoVO);
                //发送短信给客户
                sendCtrMsg(nlsCreditInfoVO);

                try {
                    //回写公积金接口
                    yedGjjLoanService.callSyncGjjInvoteCredit(nlsCreditInfoVO);
                } catch (Exception e) {
                    logger.error("授信申请流水号【 " + nlsCreditInfoVO.getLmtApplySeq() + "】，全局流水号【" + nlsCreditInfoVO.getGlobalSerno() + "】，同步公积金接口失败！");
                    throw new Exception("授信生成额度后同步公积金接口失败");
                }

            }
        } catch (Exception e) {
            /** 设置审批状态信息为拒绝 **/
            nlsCreditInfoVO.setApprvSts(MsLoanConstant.NlsApplyStateEnum.REJECT.getVALUE());
            nlsCreditInfoVO.setRefuseCause(e.getMessage());
            sendToRisk(nlsCreditInfoVO);
            nlsProcessBizVo.setExceptionFlag(Boolean.TRUE);
            nlsProcessBizVo.setSoltName30("1");
            nlsProcessBizVo.setRefuseMsg(e.getMessage());
            nlsProcessBizVo.setExceptionMsg(e);
        } finally {
            logger.info("======>优e贷生成额度信息服务结束,流水号" + applySeq + "<======");
        }

    }


    /**
     * 更新授信状态为通过: <br>
     * <p>
     * 0.1:caoxin:2019/4/23 10:21: TODO: <br>
     *
     * @return
     * @author caoxin
     * @date 2019/4/23 10:21
     * @version 0.1
     * @since 2019/4/23 10:21
     */
    private void updateCreditApplyInfo(NlsCreditInfoVO nlsCreditInfoVO) throws BizException {
        // 更新授信状态为通过
        nlsCreditInfoVO.setApprvSts(ConsoleConstant.NLSCREDIT_PASS);
        // 设置更新默认值
        setServerUpdateDefaultProperty(nlsCreditInfoVO);
        int result = nlsCreditInfoService.updateByPk(nlsCreditInfoVO);
        if (result == -1) {
            throw new BizException("更新授信信息失败");
        }
    }

    private void updateCreditApplyInfoErr(NlsCreditInfoVO nlsCreditInfoVO) throws BizException {
        // 更新授信状态为通过
        nlsCreditInfoVO.setApprvSts(ConsoleConstant.NLSCREDIT_REJECT);
        // 设置更新默认值
        setServerUpdateDefaultProperty(nlsCreditInfoVO);
        int result = nlsCreditInfoService.updateByPk(nlsCreditInfoVO);
        if (result == -1) {
            throw new BizException("更新授信信息失败");
        }
    }


    /**
     * 插入未生效的额度信息: <br>
     * <p>
     * 0.1:caoxin:2019/4/23 9:54: TODO: <br>
     *
     * @return
     * @author caoxin
     * @date 2019/4/23 9:54
     * @version 0.1
     * @since 2019/4/23 9:54
     */
    private void insertProLmtCont(NlsCreditInfoVO nlsCreditInfoVO,String openday) throws BizException {
        // 网贷申请信息不能为空
        Objects.requireNonNull(nlsCreditInfoVO, "【额度生成插槽】授信申请信息为空!!!");
        logger.info("======>【额度生成插槽】插入授信协议表开始" + nlsCreditInfoVO.getLmtApplySeq() + "<======");
        LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
        // 生成Lmt流水号
        lmtPrdContVO.setLmtContNo(generateLmtContNo());
        // 来源授信申请信息 授信申请流水号
        lmtPrdContVO.setLmtApplySeq(nlsCreditInfoVO.getLmtApplySeq());
        // 来源授信申请信息 客户ID
        lmtPrdContVO.setCusId(nlsCreditInfoVO.getCusId());
        // 来源授信申请信息 客户姓名
        lmtPrdContVO.setCusName(nlsCreditInfoVO.getCusName());
        // 来源授信申请信息 客户证件类型
        lmtPrdContVO.setCertType(nlsCreditInfoVO.getCertType());
        // 来源授信申请信息 客户身份证
        lmtPrdContVO.setCertCode(nlsCreditInfoVO.getCertCode());
        // 来源授信申请信息 渠道号
        lmtPrdContVO.setChannelNo(nlsCreditInfoVO.getChannelNo());
        // 来源授信申请信息 产品ID
        lmtPrdContVO.setPrdId(nlsCreditInfoVO.getPrdId());
        // 来源授信申请信息 产品编号
        lmtPrdContVO.setPrdCode(nlsCreditInfoVO.getPrdCode());
        // 来源授信申请信息 产品名称
        lmtPrdContVO.setPrdName(nlsCreditInfoVO.getPrdName());
        // 来源授信申请信息 审批金额
        lmtPrdContVO.setLmtAmt(nlsCreditInfoVO.getApproveAmt());
        // 来源授信申请信息 可用额度
        lmtPrdContVO.setAvailAmt(nlsCreditInfoVO.getApproveAmt());
        // 来源授信申请信息 是否循环
        lmtPrdContVO.setCyclicFlg(nlsCreditInfoVO.getCyclicFlg());
        // 来源授信申请信息 币种
        lmtPrdContVO.setCurrencyType(nlsCreditInfoVO.getCurrencyType());
        // 来源授信申请信息 期限
        if (!StringUtil.isNullorBank(nlsCreditInfoVO.getApplyTerm())){
            lmtPrdContVO.setTerm(new BigDecimal(nlsCreditInfoVO.getApplyTerm()));
        }
        // 来源授信申请信息 期限类型
        lmtPrdContVO.setTermType(nlsCreditInfoVO.getTermType());
        // 来源授信申请信息 担保方式
        lmtPrdContVO.setAssureMeansMain(nlsCreditInfoVO.getAssureMeansMain());
        // 来源授信申请信息 贷款用途
        //lmtPrdContVO.setLoanUse(nlsCreditInfoVO.getLoanUseType());
        // 来源授信申请信息 额度状态为有效
        lmtPrdContVO.setLmtStatus(ConsoleConstant.LIMIT_STS_02);
        // 利率
        lmtPrdContVO.setRateY(nlsCreditInfoVO.getApproveRateY());

        // 起始日期
        lmtPrdContVO.setStartDate(openday);
        // 到期日期 openDay+期限
        try {
            lmtPrdContVO.setExpireDate(TimeUtil.addMonth(openday, 12));
        } catch (Exception e) {
            throw new BizException("【额度生成服务】授信协议表到期日期设置失败!!!");
        }

        setServerInsertDefaultProperty(lmtPrdContVO);
        lmtPrdContVO.setLegalOrgCode("0010");
        lmtPrdContVO.setLegalOrgName("广州银行智慧中心");
        int result = lmtPrdContService.insertLmtPrdCont(lmtPrdContVO);
        if (result == -1) {
            throw new BizException("=======>【额度生成服务】生成额度插槽,插入未生效的额度信息失败<=======", msgTemplate);
        }else {
            //异步送风控大数据
            sendToRisk(lmtPrdContVO);
        }
    }

    /**
     *  异步送风控大数据
     * @param lmtPrdContVO
     */
    private void sendToRisk(LmtPrdContVO lmtPrdContVO) {
        // 授信申请流水号
        String applySeq = lmtPrdContVO.getLmtApplySeq();
        logger.info("【额度生成服务】授信协议表，发送kafka消息给大数据开始执行,流水号:" + applySeq);
        try{
            boolean flag = false;
            //查询开关
            List<NlsStageInfoVO> infoVOS = nlsStageInfoService.queryList();
            for(NlsStageInfoVO vo:infoVOS){
                if(vo.getPrdId().equals("11110004") && vo.getStatus().equals("on") && vo.getStage().equals("credit")){
                    flag = true;
                }
            }
            LmtPrdContNoticeVO array = new LmtPrdContNoticeVO();
            JSONObject jsonObject = new JSONObject();
            array.setTableName("LMT_PRD_CONT");
            array.setLmtApplySeq(lmtPrdContVO.getLmtApplySeq());
            array.setLmtContNo(lmtPrdContVO.getLmtContNo());
            array.setCreateTime(lmtPrdContVO.getCreateTime());
            array.setLmtAmt(lmtPrdContVO.getLmtAmt());
            array.setTerm(lmtPrdContVO.getTerm());
            array.setRateY(lmtPrdContVO.getRateY());
            //数据日期
            String timeStamp = TimeUtil.getTimeStampByPattern("yyyy-MM-dd HH:mm:ss");
            array.setDataTime(timeStamp);

            KafkaNoticeHeader header = new KafkaNoticeHeader();
            header.setMessageCode("YED_JISHI");
            header.setTimestamp(timeStamp);
            header.setTransactionId(getTransactionId());
            header.setSysName("netLoan");

            jsonObject.put("head", header);
            jsonObject.put("biz", array);
            if(!flag){
                logger.info("实时采集开关未打开！！！");
                return;
            }
            threadPool.add(() -> {
                KafkaUtil kafkaUtil = new KafkaUtil(kafkaServers,kafkaToptic);
                try{
                    kafkaUtil.sendMessage(JSONObject.toJSONString(jsonObject));
                }catch (Exception e){
                    e.printStackTrace();
                    logger.error("【额度生成服务】授信协议表，发送kafka消息给大数据失败，流水号："+ applySeq +",异常信息："+e.getMessage());
                }
            });
        }catch (Exception e){
            logger.info("【额度生成服务】授信协议表，发送kafka消息给大数据异常，流水号："+ applySeq +",异常信息："+e.getMessage());
        }finally {
            logger.error("【额度生成服务】授信协议表，发送kafka消息给大数据结束，流水号："+ applySeq);
        }
    }

    private void sendToRisk(NlsCreditInfoVO nlsCreditInfoVO) {
        // 授信申请流水号
        String applySeq = nlsCreditInfoVO.getLmtApplySeq();
        logger.info("优e贷授信，发送kafka消息给大数据开始执行,流水号:" + applySeq);
        try {
            boolean flag = false;
            //查询开关
            List<NlsStageInfoVO> infoVOS = nlsStageInfoService.queryList();
            for(NlsStageInfoVO vo:infoVOS){
                if(vo.getPrdId().equals("11110004") && vo.getStatus().equals("on") && vo.getStage().equals("credit")){
                    flag = true;
                }
            }
            JSONObject jsonObject = new JSONObject();
            NlsCreditInfoNoticeVO array = new NlsCreditInfoNoticeVO();
            array.setTableName("NLS_CREDIT_INFO");
            //数据日期
            String timeStamp = TimeUtil.getTimeStampByPattern("yyyy-MM-dd HH:mm:ss");
            array.setApprvSts(nlsCreditInfoVO.getApprvSts());
            array.setLmtApplySeq(nlsCreditInfoVO.getLmtApplySeq());
            array.setRefuseCause(nlsCreditInfoVO.getRefuseCause());
            array.setDataTime(timeStamp);

            KafkaNoticeHeader header = new KafkaNoticeHeader();
            header.setMessageCode("YED_JISHI");
            header.setTimestamp(timeStamp);
            header.setTransactionId(getTransactionId());
            header.setSysName("netLoan");

            jsonObject.put("head", header);
            jsonObject.put("biz", array);

            if(!flag){
                logger.info("实时采集开关未打开！！！");
                return;
            }
            threadPool.add(() -> {
                KafkaUtil kafkaUtil = new KafkaUtil(kafkaServers, kafkaToptic);
                try {
                    kafkaUtil.sendMessage(JSONObject.toJSONString(jsonObject));
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error("优e贷授信，发送kafka消息给大数据失败，流水号：" + applySeq + ",异常信息：" + e.getMessage());
                }
            });
        } catch (Exception e) {
            logger.info("优e贷授信，发送kafka消息给大数据异常，流水号：" + applySeq + ",异常信息：" + e.getMessage());
        } finally {
            logger.info("优e贷授信，发送kafka消息给大数据结束，申请流水号：" + applySeq);
        }
    }

    public static String getTransactionId() {
        String transactionId = "SEQ" + DateFormatUtils.format(new Date(), DateFormatConstant.DATETIME_FORMAT_COMPACT, Locale.CHINA) +
                RandomCodeUtils.generateLetter(6);
        return transactionId;
    }
    /**
     * 通过授信申请流水号获取授信协议信息: <br>
     * <p>
     * 0.1:caoxin:2019/4/23 9:34: TODO: <br>
     *
     * @return
     * @author caoxin
     * @date 2019/4/23 9:34
     * @version 0.1
     * @since 2019/4/23 9:34
     */

    private boolean getLimitByLmtApplySeq(NlsCreditInfoVO nlsCreditInfoVO) {
        LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
        lmtPrdContVO.setLmtApplySeq(nlsCreditInfoVO.getLmtApplySeq());
        lmtPrdContVO = lmtPrdContService.queryByPk(lmtPrdContVO);
        return lmtPrdContVO == null;
    }

    /**
     * 生成LMT系统的交易流水号: <br>
     * <p>
     * 0.1:heyingfeng:2019/4/23 9:58: <br>
     *
     * @return
     * @author heyingfeng
     * @date 2019/4/23 9:58
     * @version 0.1
     * @since 2019/4/23 9:58
     */

    private String generateLmtContNo() {
        PatternedLimitableSeqService sequenceService = SpringContextUtils.getBean(PatternedLimitableSeqService.class);
        return sequenceService.getPatternedSequence("LMT", PATTERN);
    }


    /**
     * 授信通过后发送短信给客户
     *
     * @param nlsCreditInfoVO
     */
    private  void sendCtrMsg(NlsCreditInfoVO nlsCreditInfoVO) {
        String msg = "【广州银行】尊敬的"+nlsCreditInfoVO.getCusName()+"，您申请的（"+nlsCreditInfoVO.getPrdName()+"）已通过审核，额度：" +
                "人民币（"+nlsCreditInfoVO.getApproveAmt()+"）元，点击"+url+"可快速查询，详询020-96699。";
        final ReqSedLetterBean reqSedLetterBean = new ReqSedLetterBean();
        reqSedLetterBean.setMblNo(nlsCreditInfoVO.getIndivMobile());
        reqSedLetterBean.setCntntInf(msg);
        try {
            sedLetterInformService.sendLetter(reqSedLetterBean);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("优e贷授信通过下发短信异常：", e);
        }
    }

    /**
     * 插入客户推荐人信息表
     * @param nlsCreditInfoVO
     * @param openday
     * @throws BizException
     */
    private void updateCusReferrerInfo(NlsCreditInfoVO nlsCreditInfoVO,String openday) throws BizException {
        String expireDate="";
        try {
             expireDate=TimeUtil.addMonth(openday, 12);
        } catch (Exception e) {
            e.printStackTrace();
        }
        CusReferrerInfoVO cus=CusReferrerInfoVO.builder()
                //授信申请流水号
                .lmtApplySeq(nlsCreditInfoVO.getLmtApplySeq())
                //工作单位名称
                .wrkCorpNm(nlsCreditInfoVO.getWrkCorpNm())
                //授信有效期起始日
                .startDate(openday)
                //授信有效期到期日
                .expireDate(expireDate)
                //最后修改时间
                .lastModifyTime(TimeUtil.getCurrentDateTime())
                .build();
        int result = cusReferrerInfoService.updateByPk(cus);
        if (result == -1) {
            throw new BizException("=======>【优e贷额度生成服务】更新客户推荐人信息表失败<=======");
        }
    }

    /**
     * 额度信息服务
     */
    @Autowired
    @Qualifier("lmtPrdContService")
    private LmtPrdContService lmtPrdContService;

    /**
     * 授信信息服务
     */
    @Autowired
    @Qualifier("nlsCreditInfoService")
    private NlsCreditInfoService nlsCreditInfoService;


    @Autowired
    @Qualifier("pubSysInfoService")
    private PubSysInfoService pubSysInfoService;

    @Autowired
    @Qualifier("sedLetterInformService")
    private SedLetterInformService sedLetterInformService;

    @Autowired
    @Qualifier("applicationThreadPool")
    private ApplicationThreadPool2 threadPool;

    @Autowired
    @Qualifier("cusReferrerInfoService")
    private CusReferrerInfoService cusReferrerInfoService;

    @Autowired
    @Qualifier("nlsStageInfoService")
    private NlsStageInfoService nlsStageInfoService;
    @Autowired
    private YedGjjLoanService yedGjjLoanService;
    @Autowired
    private YedSxCtrSignatureService yedSxCtrSignatureService;
    @Autowired
    private YedSqsSignatureService yedSqsSignatureService;


}
